# -*- encoding: utf-8 -*-
from odoo import models, fields, api, _
from odoo.addons import base_cw
from odoo.exceptions import UserError


class account_cash_dialy(models.Model):
    _name = 'account.cash.dialy'
    _description = u'出纳日记帐'
    _order = 'date,id'

    @api.depends('line_ids', 'line_ids.debit', 'line_ids.credit')
    def _compute_debit_credit(self):
        for record in self:
            record.total_debit = sum(record.line_ids.mapped('debit'))
            record.total_credit = sum(record.line_ids.mapped('credit'))

    name = fields.Char(u'单据编号', required=True, default='New', copy=False)
    date = fields.Date(u'单据日期', default=fields.Date.context_today, required=True)
    note = fields.Text(u'备注')
    origin = fields.Char(u'来源单据', compute='compute_origin', store=True, readonly=False)
    confirm_date = fields.Datetime(u'确认日', readonly=True)
    confirm_user_id = fields.Many2one('res.users', u'确认人', required=False, readonly=True)
    audit_date = fields.Datetime(u'审核日', readonly=True)
    audit_user_id = fields.Many2one('res.users', u'审核人', required=False, readonly=True)
    company_id = fields.Many2one('res.company', string=u'公司', change_default=True,
                                 required=True, readonly=True, states={'draft': [('readonly', False)]},
                                 default=lambda self: self.env.company)
    state = fields.Selection([('draft', u'草稿'),
                              ('confirmed', u'已确认'),
                              ('audited', u'已审核'),
                              ('cancel', u'已取消'), ], u'单据状态', required=True, default='draft',
                             tracking=True)
    account_id = fields.Many2one('cncw.account', u'会计科目', required=True, ondelete="restrict")
    currency_id = fields.Many2one(related='account_id.currency_id', string=u'币别')
    line_ids = fields.One2many('account.cash.dialy.line', 'master_id', u'日记帐明细', copy=True)
    begin = fields.Monetary(u'期初金额', currency_id='currency_id', default=0)
    total_debit = fields.Monetary(u'收入', compute='_compute_debit_credit', currency_id='currency_id', store=True)
    total_credit = fields.Monetary(u'支出', compute='_compute_debit_credit', currency_id='currency_id', store=True)
    balance = fields.Monetary(u'余额', currency_id='currency_id', default=0)
    period_id = fields.Many2one('account.period', u'期别', states={'audited': [('readonly', True)]})
    done_user_id = fields.Many2one('res.users', string='完成人')
    done_date = fields.Datetime(u'完成日', readonly=True)
    pay_order_id = fields.Many2one('account.pay', string='付款单', states={'audited': [('readonly', True)]})
    receive_order_id = fields.Many2one('account.receive', string='收款单', states={'audited': [('readonly', True)]})
    res_partner_id = fields.Many2one('res.partner', string=u'往来单位', compute='_compute_pay_order', store=True)

    @api.depends('pay_order_id', 'receive_order_id')
    def compute_origin(self):
        """计算来源单据"""
        for record in self:
            if record.pay_order_id or record.receive_order_id:
                record.origin = record.pay_order_id.name or record.receive_order_id.name
            else:
                record.origin = ''

    @api.model
    def create(self, vals):
        base_cw.public.generate_voucher_no(self, vals)
        return super(account_cash_dialy, self).create(vals)

    @api.depends('pay_order_id', 'receive_order_id')
    def _compute_pay_order(self):
        if self.pay_order_id:
            self.res_partner_id = self.pay_order_id.partner_id
        if self.receive_order_id:
            self.res_partner_id = self.receive_order_id.partner_id
        # self.flush()

    @api.onchange('date')
    def onchange_date(self):
        if self.date:
            period_id = self.env['account.period'].search(
                [('date_start', '<=', self.date), ('date_stop', '>=', self.date)], limit=1)
            self.period_id = period_id and period_id.id or False

    @api.model
    def period_state_check(self):
        self.env['account.period'].period_state_check(self._name, date=self.date, belongs_to_module='gl')

    #  计算期初和余额
    @api.model
    def compute_begin_and_balance(self):
        begin_amount = 0.0
        # if self.env['account.cash.dialy'].search(
        #         [('date', '=', self.date), ('account_id', '=', self.account_id.id), ('id', '!=', self.id)]):
        #     raise UserError(_(u'当天存在相同会计科目的单据!'))
        if self.period_id and self.account_id:
            cash_dialy = self.env['account.cash.dialy'].search(
                [('account_id', '=', self.account_id.id), ('period_id', '=', self.period_id.id),
                 ('state', 'in', ('confirmed', 'audited')), ('date', '<=', self.date), ('id', '!=', self.id)], )
            if len(cash_dialy) == 0:
                prior_period_id = self.period_id.pre_period_id.id or False
                begin_amount = prior_period_id and self.env['account.cash.monthly'].search(
                    [('account_id', '=', self.account_id.id), ('period_id', '=', prior_period_id)]).balance
            else:
                begin_amount = cash_dialy[-1].balance
        self.balance = begin_amount + self.total_debit - self.total_credit
        self.begin = begin_amount

    def action_confirm(self):
        """
        :return:
        """
        self.ensure_one()
        self._cr.commit()
        self.compute_begin_and_balance()
        state = 'confirmed'
        self.write(dict(confirm_user_id=self._uid,
                        confirm_date=fields.datetime.utcnow(),
                        state=state))
        self.action_audit()

    # 取消确认
    def action_cancel_confirm(self):
        self.ensure_one()
        self.action_cancel_audit()
        state = 'draft'
        self.write(dict(confirm_user_id=False,
                        confirm_date=None,
                        state=state))

    # 审核
    def action_audit(self):
        """
        :return:
        """
        self.ensure_one()
        # self.assert_balanced()
        for voucher in self:
            voucher.period_state_check()
            state = 'audited'
            voucher.write(dict(done_user_id=self.env.user.id,
                               done_date=fields.datetime.utcnow(),
                               state=state))

    # 取消审核
    def action_cancel_audit(self):
        """
        :return:
        """
        for voucher in self:
            voucher.period_state_check()
            state = 'draft'
            voucher.write(dict(confirm_user_id=False,
                               confirm_date=None,
                               audit_user_id=False,
                               audit_date=None,
                               state=state))
            self.begin = 0.0
            self.balance = 0.0

    def unlink(self):
        if self.state != 'draft':
            raise UserError(_(u'出纳日记账只能删除草稿状态的单据!'))
        res = super(account_cash_dialy, self).unlink()
        return res


class account_cash_dialy_line(models.Model):
    _name = 'account.cash.dialy.line'
    _description = u'日记帐明细'

    @api.depends('account_id')
    def _get_sub_account_ids(self):
        account_obj = self.env['cncw.account']
        self.sub_account_ids = account_obj.get_sub_account_ids(self.account_id)

    master_id = fields.Many2one('account.cash.dialy', u'出纳日记账', ondelete="cascade")
    sequence = fields.Integer(u'项次', default=1)
    dc_type = fields.Selection([('D', u'收入'), ('C', u'支出')], u'收支', default='D')
    account_id = fields.Many2one(related='master_id.account_id', string=u'会计科目', ondelete="restrict")
    sub_account_id = fields.Many2one('res.partner', u'现金流项目', ondelete="restrict")
    sub_account_type = fields.Selection(base_cw.public.SUB_ACCOUNT_TYPE, u'辅助核算类型',
                                        related='account_id.sub_account_type')
    sub_account_ids = fields.Many2many('res.partner', compute='_get_sub_account_ids', string=u'可选辅助核算')
    name = fields.Char(u'摘要')
    origin = fields.Char(u'来源单据', compute='compute_origin', store=True, readonly=False)
    date = fields.Date(u'日期')
    remark_id = fields.Many2one('account.voucher.remark', u'常用', ondelete="set null", store=False)
    currency_id = fields.Many2one(related='account_id.currency_id', string=u'币别')
    exchange_rate = fields.Float(u'汇率', digits='Exchange Rate', defualt=1.0)
    debit = fields.Monetary(u'收入', currency_id='currency_id', default=0, compute='_compute_debit_credit', store=True,
                            readonly=False)
    credit = fields.Monetary(u'支出', currency_id='currency_id', default=0, compute='_compute_debit_credit', store=True,
                             readonly=False)
    company_currency_id = fields.Many2one('res.currency', u'币别',
                                          default=lambda self: self.env.user.company_id.currency_id)

    lc_debit = fields.Monetary(u'本币收入', currency_id='company_currency_id', default=0)
    lc_credit = fields.Monetary(u'本币支出', currency_id='company_currency_id', default=0)
    state = fields.Selection([('draft', u'草稿'),
                              ('confirmed', u'已确认'),
                              ('audited', u'已审核'),
                              ('cancel', u'已取消'), ], u'状态', related='master_id.state', readonly=True)
    company_id = fields.Many2one('res.company', string=u'公司', change_default=True,
                                 required=True, readonly=True, states={'draft': [('readonly', False)]},
                                 default=lambda self: self.env.company)
    report_seq = fields.Integer(u'序')
    balance = fields.Float(u'余额', digits='Amount', default=0)
    cash_monthly_id = fields.Many2one('account.cash.monthly', u'出纳日记帐月汇总', help=u'在日记帐月结时写入', ondelete="set null")
    sub_account_lines = fields.One2many('sub.account.line', 'cash_dialy_line_id')
    sub_account_lines_str = fields.Char(string=u'会计辅助核算', compute='compute_sub_account_lines_str')

    @api.depends('master_id.pay_order_id', 'master_id.receive_order_id')
    def compute_origin(self):
        """计算来源单据"""
        for record in self:
            if record.master_id.pay_order_id or record.master_id.receive_order_id:
                record.origin = record.master_id.pay_order_id.name or record.master_id.receive_order_id.name
            else:
                record.origin = ''

    def edit_sub_account_lines(self):
        return {
            "type": "ir.actions.act_window",
            "res_model": "account.cash.dialy.line",
            'view_mode': 'form',
            'view_id': self.env.ref('cncw_ledger.view_account_voucher_line_form2').id,
            "res_id": self.id,
            "name": "编辑辅助核算",
            "target": 'new'
        }

    @api.depends('dc_type', 'master_id.pay_order_id', 'master_id.receive_order_id', 'account_id')
    def _compute_debit_credit(self):
        for record in self:
            pay_order_id = record.master_id.pay_order_id
            receive_order_id = record.master_id.receive_order_id
            if pay_order_id:
                record.dc_type = 'C'
                record.debit = 0
                record.credit = self._get_amount()
                record.lc_debit = 0
                record.lc_credit = self._get_local_amount()
            elif receive_order_id:
                record.dc_type = 'D'
                record.credit = 0
                record.debit = self._get_amount()
                record.lc_credit = 0
                record.lc_debit = self._get_local_amount()
            else:
                record.credit = 0
                record.lc_credit = 0
                record.debit = 0
                record.lc_debit = 0

    def _get_amount(self):
        """
        获取借贷方原币
        :return:
        """
        for record in self:
            amount = sum(
                record.master_id.pay_order_id.line_ids
                    .filtered(lambda x: x.account_id.id == record.master_id.account_id.id)
                    .mapped('amount')
            ) or sum(
                record.master_id.receive_order_id.line_ids
                    .filtered(lambda x: x.account_id.id == record.master_id.account_id.id)
                    .mapped('amount')
            )
            return amount

    def _get_local_amount(self):
        """
        获取借贷方本币
        :return:
        """
        for record in self:
            amount = sum(
                record.master_id.pay_order_id.line_ids
                    .filtered(lambda x: x.account_id.id == record.master_id.account_id.id)
                    .mapped('local_amount')
            ) or sum(
                record.master_id.receive_order_id.line_ids
                    .filtered(lambda x: x.account_id.id == record.master_id.account_id.id)
                    .mapped('local_amount')
            )
            return amount

    def compute_sub_account_lines_str(self):
        for record in self:
            sub_account_lines_str = ''
            for line in record.sub_account_lines.filtered(lambda r: r.sub_account_id):
                sub_account_lines_str += ' | '+line.sub_account_id.name
                if line.category_id.code == 'cash_flow':
                    record.sub_account_id = line.sub_account_id
            record.sub_account_lines_str = sub_account_lines_str

    @api.constrains('debit', 'debit')
    def _check_debit_debit(self):
        if (abs(self.debit) > 0 and abs(self.credit) > 0) or (abs(self.lc_debit) > 0 and abs(self.lc_credit) > 0):
            raise UserError(_(u'收入支出不可同时有值.'))

    #
    # @api.model
    # def create(self, vals):
    #     base_cw.public.generate_sequence(self, vals)
    #     return super(account_cash_dialy_line, self).create(vals)

    @api.model
    def create(self, vals):
        master_id = self.env['account.cash.dialy'].browse(vals['master_id'])
        if master_id.period_id.id:
            self._cr.execute(
                'select max(a.sequence) from account_cash_dialy_line a left join account_cash_dialy b on b.id=a.master_id '
                'where b.period_id=%s and b.account_id=%s',
                (master_id.period_id.id, master_id.account_id.id))
            seq = self._cr.fetchone()[0]
            vals['sequence'] = seq and seq + 1 or 1
        if master_id.res_partner_id:
            line_val = {'category_id': master_id.res_partner_id.subaccount_category_id.id,
                        'sub_account_id': master_id.res_partner_id.id}
            vals['sub_account_lines'] = [(0, 0, line_val)]
        return super(account_cash_dialy_line, self).create(vals)

    @api.onchange('dc_type')
    def onchange_dc_type(self):
        if self.dc_type == 'D':  # 借方
            self.lc_credit = self.credit = 0.0
        else:
            self.lc_debit = self.debit = 0.0

    @api.onchange('currency_id')
    def onchangge_currency_id(self):
        if self.currency_id:
            self.exchange_rate = self.currency_id.rate or 1.0
        else:
            self.exchange_rate = 1.0

    @api.onchange('remark_id')
    def onchangge_remark_id(self):
        if self.remark_id:
            self.name = self.remark_id.name

    @api.onchange('account_id')
    def onchangge_account_id(self):
        if self.account_id and self.account_id.name == '现金':
            if self.account_id.name == '现金':
                self.dc_type = 'C'
            if self.account_id.sub_account_type != 'has':
                self.sub_account_id = False

    @api.onchange('exchange_rate')
    def onchange_exchange_rate(self):
        if self.exchange_rate != 0.0:
            self.lc_debit = self.debit * self.exchange_rate
            self.lc_credit = self.credit * self.exchange_rate
        else:
            self.lc_debit = self.debit
            self.lc_credit = self.credit

    @api.onchange('credit')
    def onchange_credit(self):
        if self.exchange_rate != 0.0:
            self.lc_credit = self.credit * self.exchange_rate
        else:
            self.lc_credit = self.credit

    @api.onchange('debit')
    def onchange_debit(self):
        if self.exchange_rate != 0.0:
            self.lc_debit = self.debit * self.exchange_rate
        else:
            self.lc_debit = self.debit

    def write(self, vals):
        if vals.get('account_id', False):
            account = self.env['cncw.account'].browse(vals.get('account_id'))
            if account:
                if account.sub_account_type != 'has':
                    self.sub_account_id = False
                elif account.sub_account_type == 'has':
                    if not self.sub_account_id:
                        raise UserError(_(u'会科%s 为有辅助核算会科,请输入辅助核算!' % (account.code,)))
        res = super(account_cash_dialy_line, self).write(vals)
        return res
